﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Eqwww.Code;
using Eqwww.Data;
using Eqwww.Domain;
using Eqwww.Domain.Models.SystemManage;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Identity;
using Eqwww.Domain.Models.Identity;
using System.ComponentModel;

namespace Eqwww.App.SystemManage
{
    public class PostApp
    {
        private ApplicationDbContext _context;
        private IModelHandler _modelHandler;
        private DatabaseLogApp _dbLogApp;
        private UserManager<UserModel> _userManager;
        public PostApp(ApplicationDbContext context, IModelHandler modelHandler, DatabaseLogApp databaseLogApp, UserManager<UserModel> userManager)
        {
            _context = context;
            _modelHandler = modelHandler;
            _dbLogApp = databaseLogApp;
            _userManager = userManager;
        }

        /// <summary>
        /// 新建
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public async Task<ModelResult> CreateAsync(PostModel model)
        {
            if (IsExistCode(model.Code))
                return Common.ErrorResult("编码已经存在");

            _modelHandler.Create(model);
            _context.Sys_Posts.Add(model);
            _dbLogApp.LogCreateInformation(model.Id, model,"创建岗位");
            await _context.SaveChangesAsync();
            return Common.SuccessResult();
        }

        /// <summary>
        /// 更新
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public async Task<ModelResult> UpdateAsync(PostModel model)
        {
            var oldModel = await GetAsync(model.Id);
            if (oldModel == null)
                return Common.ErrorResult("未找到要更新的实体");

            if (IsExistCode(model.Code, model.Id))
                return Common.ErrorResult("编码已经存在");

            if (GetDescendantIdsWithSelf(model.Id).Contains(model.ParentId))
                return Common.ErrorResult("不能将上级岗位设置为自身或子孙岗位");

            oldModel.Code = model.Code;
            oldModel.Name = model.Name;
            oldModel.SortCode = model.SortCode;
            oldModel.JobId = model.JobId;
            oldModel.OrganizeId = model.OrganizeId;
            oldModel.ParentId = model.ParentId;
            oldModel.Job = null;
            oldModel.Organize = null;
            oldModel.Parent = null;

            _modelHandler.Update(oldModel);
            _context.Sys_Posts.Update(oldModel);
            _dbLogApp.LogUpdateInformation(oldModel.Id, oldModel,"更新岗位");
            await _context.SaveChangesAsync();
            return Common.SuccessResult();
        }

        /// <summary>
        /// 移除岗位，当岗位包含人员时不允许移除
        /// </summary>
        /// <param name="jobId"></param>
        /// <returns></returns>
        public async Task<ModelResult> RemoveAsync(string postId)
        {

            var model = _context.Sys_Posts.FirstOrDefault(x => x.Id == postId);
            if (model == null)
                return Common.ErrorResult("指定Id的岗位不存在");

            if (_context.Sys_Posts.Any(x => x.ParentId == postId && x.DeleteMark != true))
                return Common.ErrorResult("当前岗位有下级岗位，不能移除");

            var userPosts = from p in _context.Sys_UserPosts.Where(x => x.PostId == postId)
                            select p.UserId;
            if (_userManager.Users.Any(x => userPosts.Contains(x.Id) && x.DeleteMark != true))
                return Common.ErrorResult("当前岗位被人员引用，不能移除");

            _modelHandler.Delete(model);
            _context.Sys_Posts.Update(model);
            _dbLogApp.LogRemoveInformation(postId, model,"逻辑删除岗位");
            await _context.SaveChangesAsync();
            return Common.SuccessResult();
        }

        

        public async Task<PostModel> GetAsync(string id, bool containDeleted = false)
        {
            var expression = ExtLinq.True<PostModel>();
            if (!containDeleted)
                expression = expression.And(x => x.DeleteMark != true);
            expression = expression.And(x => x.Id == id);

            return await _context.Sys_Posts.AsNoTracking()
            .Include(x=>x.Organize)
            .Include(x=>x.Parent)
            .Include(x=>x.Job)
            .Include(x=>x.CreateUser)
            .Include(x=>x.LastUpdateUser)
            .Include(x=>x.DeleteUser)
            .FirstOrDefaultAsync(expression);
        }

        

        /// <summary>
        /// 获取包含自身的子孙岗位列表Id
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public IEnumerable<string> GetDescendantIdsWithSelf(string id, bool containDeleted = false)
        {
            var data = _context.Sys_Posts.AsNoTracking();
            if (containDeleted == false)
                data = data.Where(x => x.DeleteMark != true);

            var list = new List<string>();
            if (string.IsNullOrEmpty(id))
                return list;
            list.Add(id);
            var childrenIds = (from p in data.Where(x => x.ParentId == id) select p.Id).ToList();
            if (childrenIds.Count() <= 0)
                return list;
            else
            {
                foreach (var item in childrenIds)
                {
                    list.AddRange(GetDescendantIdsWithSelf(item));
                }
            }
            return list;
        }

        /// <summary>
        /// 检查指定code是否存在
        /// </summary>
        /// <param name="code"></param>
        /// <returns></returns>
        public bool IsExistCode(string code)
        {
            return _context.Sys_Posts.Any(x => x.Code.ToLower() == code.ToLower());
        }

        /// <summary>
        /// 检查指定code是否存在
        /// </summary>
        /// <param name="code"></param>
        /// <param name="strategoryId"></param>
        /// <returns></returns>
        public bool IsExistCode(string code, string postId)
        {
            return _context.Sys_Posts.Any(x => x.Code.ToLower() == code.ToLower() && x.Id != postId);
        }

        ///获取全部岗位列表
        public List<PostModel> GetList()
        {
            return _context.Sys_Posts.AsNoTracking()
            .Include(x=>x.Organize)
            .Include(x=>x.Parent)
            .Include(x=>x.Job)
            .Where(x=>x.DeleteMark!=true).ToList();
        }

        ///获取全部岗位列表
        public List<PostModel> GetList(string organizeId)
        {
            return _context.Sys_Posts.AsNoTracking()
            .Include(x => x.Organize)
            .Include(x => x.Parent)
            .Include(x => x.Job)
            .Where(x => x.DeleteMark != true&&x.OrganizeId==organizeId).OrderBy(x=>x.SortCode).ToList();
        }

        /// <summary>
        /// 岗位选择器
        /// </summary>
        /// <returns></returns>
        public IList<TreeCollapseModel> GetPostTreeCollapseItems()
        {
            var organizes = _context.IQueryable<OrganizeModel>().Where(x => x.DeleteMark != true);
            var result = (from item in organizes
                          select new TreeCollapseModel
                          {
                              Id = item.Id,
                              Text = item.Name,
                              ParentId = item.ParentId,
                              SortCode = item.SortCode,
                              Url = null,
                              Disabled = true
                          }).ToList();

            var posts = _context.IQueryable<PostModel>().Where(x => x.DeleteMark != true);
            result.AddRange((from item in posts
                             select new TreeCollapseModel
                             {
                                 Id = item.Id,
                                 Text = item.Name,
                                 ParentId = item.OrganizeId,
                                 SortCode = item.SortCode,
                                 Url = null
                             }).ToList());

            return result;
        }

        public List<TreeCollapseToggleModel> GetPostTreeCollapseToggleItemsByUserId(string userId)
        {
            var userPostIds = from p in _context.Sys_UserPosts.Where(x => x.UserId == userId) select p.PostId;
            var data = GetPostTreeCollapseToggleItems();
            foreach(var item in data)
            {
                if (userPostIds.Contains(item.Id))
                    item.ToggleMark = true;
            }
            return data;
        }

        public List<TreeCollapseToggleModel> GetPostTreeCollapseToggleItems()
        {
            var organizes = _context.IQueryable<OrganizeModel>().Where(x => x.DeleteMark != true);
            var result = (from item in organizes
                          select new TreeCollapseToggleModel
                          {
                              Id = item.Id,
                              Text = item.Name,
                              ParentId = item.ParentId,
                              SortCode = item.SortCode,
                              Url = null,
                              Disabled = true,
                               CanToggle=false,
                                Expend=true
                          }).ToList();

            var posts = _context.IQueryable<PostModel>().Where(x => x.DeleteMark != true);
            result.AddRange((from item in posts
                             select new TreeCollapseToggleModel
                             {
                                 Id = item.Id,
                                 Text = item.Name,
                                 ParentId = item.OrganizeId,
                                 SortCode = item.SortCode,
                                 Url = null,
                                 Disabled = false,
                                 CanToggle = true,
                                 Expend = true
                             }).ToList());

            return result;
        }

        public IList<PostModel> GetPagedList(string keyword, string organizeKeyword, string jobKeyword, Pagination pagination)
        {
            var exp = ExtLinq.True<PostModel>();
            exp = exp.And(x => x.DeleteMark != true);
            if (!string.IsNullOrEmpty(keyword))
                exp = exp.And(x => x.Name.Contains(keyword));
            if (!string.IsNullOrEmpty(organizeKeyword))
                exp = exp.And(x => x.Organize.Name.Contains(organizeKeyword));
            if (!string.IsNullOrEmpty(jobKeyword))
                exp = exp.And(x => x.Job.Name.Contains(jobKeyword));
            var data = _context.FindQueryable(exp, pagination)
                .Include(x => x.CreateUser)
                .Include(x => x.Parent)
                .Include(x => x.Job)
                .Include(x => x.Organize);
            return data.ToList();
        }
    }
}
